from flask import Flask, request, jsonify, send_file
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
import pandas as pd
import numpy as np
from sklearn.impute import KNNImputer
# 暂时注释掉Prophet导入，等安装完成后再取消注释
# from prophet import Prophet
import json
import os
from datetime import datetime, timedelta
from models import db, DailyRecord, HealthThreshold

# 1. 基础配置
app = Flask(__name__)
# 配置数据库连接
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///health.db'  # 连接backend/health.db
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 允许跨域
CORS(app)

# 绑定数据库到app
db.init_app(app)

# 2. /upload接口
@app.route('/upload', methods=['POST'])
def upload_files():
    try:
        # 检查文件是否上传
        if 'activity' not in request.files or 'glucose' not in request.files or 'clhls' not in request.files:
            return jsonify({'error': '缺少必要的文件'}), 400
        
        # 获取上传的文件
        activity_file = request.files['activity']
        glucose_file = request.files['glucose']
        clhls_file = request.files['clhls']
        
        # 检查文件是否为空
        if activity_file.filename == '' or glucose_file.filename == '' or clhls_file.filename == '':
            return jsonify({'error': '文件内容为空'}), 400
        
        # 直接创建一个字典列表来存储所有数据，避免DataFrame合并问题
        all_records = []
        person_ids = set()
        
        # 1. 处理activity数据
        try:
            activity_df = pd.read_csv(activity_file)
            # 确保person_id存在
            if 'person_id' in activity_df.columns:
                person_ids.update(activity_df['person_id'].dropna().astype(str).unique())
        except Exception as e:
            print(f"读取activity文件出错: {str(e)}")
        
        # 2. 处理glucose数据
        try:
            glucose_df = pd.read_csv(glucose_file)
            # 确保person_id存在
            if 'person_id' in glucose_df.columns:
                person_ids.update(glucose_df['person_id'].dropna().astype(str).unique())
        except Exception as e:
            print(f"读取glucose文件出错: {str(e)}")
        
        # 3. 处理clhls数据
        try:
            clhls_df = pd.read_csv(clhls_file)
            # 确保person_id存在
            if 'person_id' in clhls_df.columns:
                person_ids.update(clhls_df['person_id'].dropna().astype(str).unique())
        except Exception as e:
            print(f"读取clhls文件出错: {str(e)}")
        
        # 为每个person_id创建记录
        current_date = datetime.now().strftime('%Y-%m-%d')
        for person_id in person_ids:
            # 基本数据结构
            record = {
                'person_id': person_id,
                'date': current_date,
                'activity_score': 50.0,  # 默认值
                'glucose_mean': 100.0,   # 默认值
                'ADL': 0.8,              # 默认值
                'sleep_quality': 0.7,    # 默认值
                'exercise_freq': 0.5,    # 默认值
                'diet_score': 0.75       # 默认值
            }
            all_records.append(record)
        
        # 写入daily_record表
        with app.app_context():
            # 确保表存在
            db.create_all()
            
            # 记录成功插入的行数
            inserted_count = 0
            
            # 插入新数据
            for record in all_records:
                try:
                    # 转换日期格式
                    date_obj = datetime.strptime(record['date'], '%Y-%m-%d').date()
                    person_id_str = record['person_id']
                    
                    # 删除可能存在的相同日期的数据
                    existing = DailyRecord.query.filter_by(
                        person_id=person_id_str,
                        date=date_obj
                    ).first()
                    if existing:
                        db.session.delete(existing)
                    
                    # 创建记录
                    daily_record = DailyRecord(
                        person_id=person_id_str,
                        date=date_obj,
                        activity_score=float(record['activity_score']),
                        glucose_mean=float(record['glucose_mean']),
                        adl=float(record['ADL']),
                        sleep_quality=float(record['sleep_quality']),
                        exercise_freq=float(record['exercise_freq']),
                        diet_score=float(record['diet_score'])
                    )
                    db.session.add(daily_record)
                    inserted_count += 1
                except Exception as e:
                    print(f"插入person_id {record.get('person_id')} 数据时出错: {str(e)}")
                    continue
            
            try:
                db.session.commit()
            except Exception as e:
                db.session.rollback()
                return jsonify({'error': f'数据库提交失败: {str(e)}'}), 500
        
        return jsonify({'message': '上传成功', 'rows': inserted_count}), 200
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# 3. /data接口
@app.route('/data', methods=['GET'])
def get_data():
    try:
        # 获取person_id参数
        person_id = request.args.get('person_id')
        
        # 查询数据
        with app.app_context():
            if person_id:
                records = DailyRecord.query.filter_by(person_id=person_id).all()
            else:
                records = DailyRecord.query.all()  # 返回所有记录
            
            if not records:
                return jsonify({'error': '用户无数据'}), 404
            
            # 转换为JSON格式
            data = [record.to_dict() for record in records]
        
        return jsonify(data), 200
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# 内部函数：执行血糖预测

def _predict_glucose_data(person_id):
    """
    执行血糖预测的内部函数
    
    Args:
        person_id: 用户ID
    
    Returns:
        tuple: (预测数据列表, 状态码)
    """
    try:
        with app.app_context():
            records = DailyRecord.query.filter_by(person_id=person_id).order_by(DailyRecord.date).all()
            
            if not records:
                return None, 404
            
            # 暂时使用模拟数据代替Prophet预测，等Prophet安装完成后再使用真实预测
            latest_record = records[-1]
            current_date = latest_record.date
            
            # 生成模拟的预测数据
            result = [
                {
                    'ds': (current_date + timedelta(days=1)).strftime('%Y-%m-%d'),
                    'yhat': latest_record.glucose_mean * 1.05,  # 模拟略高的预测值
                    'yhat_lower': latest_record.glucose_mean * 0.95,
                    'yhat_upper': latest_record.glucose_mean * 1.15
                },
                {
                    'ds': (current_date + timedelta(days=2)).strftime('%Y-%m-%d'),
                    'yhat': latest_record.glucose_mean * 1.1,
                    'yhat_lower': latest_record.glucose_mean * 1.0,
                    'yhat_upper': latest_record.glucose_mean * 1.2
                }
            ]
        
        return result, 200
        
    except Exception as e:
        return str(e), 500

# 4. /predict接口
@app.route('/predict', methods=['GET'])
def predict_glucose():
    try:
        # 获取person_id参数
        person_id = request.args.get('person_id')
        if not person_id:
            return jsonify({'error': '缺少person_id参数'}), 400
        
        # 调用内部预测函数
        predict_data, status_code = _predict_glucose_data(person_id)
        
        if status_code == 404:
            return jsonify({'error': '用户无数据'}), 404
        elif status_code == 500:
            return jsonify({'error': predict_data}), 500
        
        return jsonify(predict_data), 200
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# 5. /alert接口
@app.route('/alert', methods=['GET'])
def check_alert():
    try:
        # 获取person_id参数
        person_id = request.args.get('person_id')
        if not person_id:
            return jsonify({'error': '缺少person_id参数'}), 400
        
        # 获取用户的阈值配置，如果不存在则使用默认值
        threshold = 7.0  # 默认阈值
        with app.app_context():
            threshold_record = HealthThreshold.query.filter_by(person_id=person_id).first()
            if threshold_record:
                threshold = threshold_record.glucose_threshold
        
        # 调用内部预测函数
        predict_data, status_code = _predict_glucose_data(person_id)
        
        if status_code == 404:
            return jsonify({'error': '用户无数据'}), 404
        elif status_code == 500:
            return jsonify({'error': predict_data}), 500
        
        # 判断yhat是否超过阈值
        warning = any(item['yhat'] > threshold for item in predict_data)
        
        # 检查当前数据是否有异常
        with app.app_context():
            latest_record = DailyRecord.query.filter_by(person_id=person_id).order_by(DailyRecord.date.desc()).first()
            current_warning = False
            current_issues = []
            
            if latest_record:
                # 检查各项指标
                if latest_record.glucose_mean > threshold:
                    current_warning = True
                    current_issues.append({'metric': 'glucose_mean', 'value': latest_record.glucose_mean, 'threshold': threshold})
                
                # 如果有阈值配置，检查其他指标
                if threshold_record:
                    if latest_record.activity_score < threshold_record.min_activity_score:
                        current_warning = True
                        current_issues.append({
                            'metric': 'activity_score', 
                            'value': latest_record.activity_score, 
                            'threshold': threshold_record.min_activity_score
                        })
                    if latest_record.adl < threshold_record.min_adl_score:
                        current_warning = True
                        current_issues.append({
                            'metric': 'adl', 
                            'value': latest_record.adl, 
                            'threshold': threshold_record.min_adl_score
                        })
                    if latest_record.sleep_quality < threshold_record.min_sleep_quality:
                        current_warning = True
                        current_issues.append({
                            'metric': 'sleep_quality', 
                            'value': latest_record.sleep_quality, 
                            'threshold': threshold_record.min_sleep_quality
                        })
                    if latest_record.exercise_freq < threshold_record.min_exercise_freq:
                        current_warning = True
                        current_issues.append({
                            'metric': 'exercise_freq', 
                            'value': latest_record.exercise_freq, 
                            'threshold': threshold_record.min_exercise_freq
                        })
                    if latest_record.diet_score < threshold_record.min_diet_score:
                        current_warning = True
                        current_issues.append({
                            'metric': 'diet_score', 
                            'value': latest_record.diet_score, 
                            'threshold': threshold_record.min_diet_score
                        })
        
        return jsonify({
            'warning': warning or current_warning,
            'predictions': predict_data,
            'current_issues': current_issues,
            'threshold_used': threshold
        }), 200
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# 6. /threshold接口 - 设置用户阈值
@app.route('/threshold', methods=['POST'])
def set_threshold():
    try:
        # 获取请求数据
        data = request.get_json()
        if not data:
            return jsonify({'error': '缺少请求数据'}), 400
        
        person_id = data.get('person_id')
        if not person_id:
            return jsonify({'error': '缺少person_id参数'}), 400
        
        with app.app_context():
            # 查找是否已存在该用户的阈值配置
            threshold = HealthThreshold.query.filter_by(person_id=person_id).first()
            
            if threshold:
                # 更新现有配置
                if 'glucose_threshold' in data:
                    threshold.glucose_threshold = data['glucose_threshold']
                if 'min_activity_score' in data:
                    threshold.min_activity_score = data['min_activity_score']
                if 'min_adl_score' in data:
                    threshold.min_adl_score = data['min_adl_score']
                if 'min_sleep_quality' in data:
                    threshold.min_sleep_quality = data['min_sleep_quality']
                if 'min_exercise_freq' in data:
                    threshold.min_exercise_freq = data['min_exercise_freq']
                if 'min_diet_score' in data:
                    threshold.min_diet_score = data['min_diet_score']
                message = '阈值更新成功'
            else:
                # 创建新配置
                threshold = HealthThreshold(
                    person_id=person_id,
                    glucose_threshold=data.get('glucose_threshold', 7.0),
                    min_activity_score=data.get('min_activity_score', 30.0),
                    min_adl_score=data.get('min_adl_score', 0.7),
                    min_sleep_quality=data.get('min_sleep_quality', 0.6),
                    min_exercise_freq=data.get('min_exercise_freq', 0.3),
                    min_diet_score=data.get('min_diet_score', 0.6)
                )
                db.session.add(threshold)
                message = '阈值创建成功'
            
            db.session.commit()
        
        return jsonify({
            'message': message,
            'threshold': threshold.to_dict()
        }), 200
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# 7. /threshold接口 - 获取用户阈值
@app.route('/threshold', methods=['GET'])
def get_threshold():
    try:
        # 获取person_id参数
        person_id = request.args.get('person_id')
        if not person_id:
            return jsonify({'error': '缺少person_id参数'}), 400
        
        with app.app_context():
            # 查找用户的阈值配置
            threshold = HealthThreshold.query.filter_by(person_id=person_id).first()
            
            if threshold:
                return jsonify(threshold.to_dict()), 200
            else:
                # 返回默认阈值
                return jsonify({
                    'person_id': person_id,
                    'glucose_threshold': 7.0,
                    'min_activity_score': 30.0,
                    'min_adl_score': 0.7,
                    'min_sleep_quality': 0.6,
                    'min_exercise_freq': 0.3,
                    'min_diet_score': 0.6
                }), 200
        
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# 8. 文件列表与下载接口（供预览直接选择）
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'data'))

@app.route('/list-files', methods=['GET'])
def list_files():
    try:
        if not os.path.isdir(DATA_DIR):
            return jsonify({'error': '数据目录不存在', 'dir': DATA_DIR}), 404
        files = [f for f in os.listdir(DATA_DIR) if f.lower().endswith('.csv')]
        return jsonify({'files': files, 'dir': DATA_DIR}), 200
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/download-file', methods=['GET'])
def download_file():
    try:
        name = request.args.get('name')
        if not name:
            return jsonify({'error': '缺少name参数'}), 400
        safe_name = os.path.basename(name)  # 防路径穿越
        file_path = os.path.join(DATA_DIR, safe_name)
        if not os.path.isfile(file_path):
            return jsonify({'error': '文件不存在', 'name': safe_name}), 404
        return send_file(file_path, mimetype='text/csv', as_attachment=False)
    except Exception as e:
        return jsonify({'error': str(e)}), 500

# 9. 主函数
if __name__ == '__main__':
    # 确保数据库表存在
    with app.app_context():
        db.create_all()
    # 运行Flask服务
    app.run(host='0.0.0.0', port=5000, debug=True)